#include "http_server_test.h"
#include <fermat/http/http_server_session.h>
#include <fermat/http/http_request.h>
#include <fermat/http/http_response_builder.h>
#include <fermat/http/http_buffered_message.h>
#include <fermat/http/http_url.h>
#include <fermat/http/http_header_builder_helper.h>
#include <fermat/common/string.h>
#include <fermat/common/logging.h>
#include <fermat/common/slice.h>
#include <fermat/common/number_parser.h>
#include <functional>
#include <memory>
#include <iostream>

namespace detail {

static char logbuf[3692];
	class BufferedResponseBuilder: public fermat::http::ResponseBuilder {
	public:
		BufferedResponseBuilder()
		{
			_senddone = false;
		}

		bool setUp()
		{
			_body = "hello world!\n";
			fermat::http::HeaderBuilderHelper bh(this);
			bh.setContentLength(_body.size());
			bh.setContentType("text/plain");
			bh.setKeepAlive(true);
			bh.setServer("fermat http");
			bh.setHeader("X-info", "11");

			bh.setHeader("X-info", "22");

			bh.setHeader("X-info", "33");
			setStatus(200);
			setMinorVersion(1);
			return true;
		}

		bool setUpBig()
		{
			static std::string buff(4096, 'x');
			_body = buff;
			fermat::http::HeaderBuilderHelper bh(this);
			bh.setContentLength(_body.size());
			bh.setContentType("text/plain");
			bh.setKeepAlive(true);
			bh.setServer("fermat http");

			bh.setHeader("X-info", "11");

			bh.setHeader("X-info", "22");

			bh.setHeader("X-info", "33");
			setStatus(200);
			setMinorVersion(1);
			return true;
		}

		bool setFixBody(int64_t len)
		{
			_body.clear();
			_body.resize(len);
			fermat::http::HeaderBuilderHelper bh(this);
			bh.setContentLength(_body.size());
			bh.setContentType("text/plain");
			bh.setKeepAlive(true);
			bh.setServer("fermat http");

			bh.setHeader("X-info", "11");

			bh.setHeader("X-info", "22");

			bh.setHeader("X-info", "33");
			setStatus(200);
			setMinorVersion(1);
			return true;

		}
		bool setRes404()
		{
			_body = "bad path!\n";
			fermat::http::HeaderBuilderHelper bh(this);
			bh.setContentLength(_body.size());
			bh.setContentType("text/plain");
			bh.setKeepAlive(true);
			bh.setServer("fermat http");

			bh.setHeader("X-info", "11");

			bh.setHeader("X-info", "22");

			bh.setHeader("X-info", "33");
			setStatus(404);
			setMinorVersion(1);
			return true;
		}

		bool isSendComplete() { return _senddone; }
		
		virtual bool sendMessage( std::string & mes)
		{
			
			mes += statusLine();
			mes += headersToString();
			mes += "\r\n";
			mes += _body;
			_senddone = true;

			LOG_INFO("response: ", mes);
			return true;
		}
	private:
		std::string _body;
		bool        _senddone;
	};

	
	bool writeResponse(fermat::http::ResponseBuilderPtr &res, std::string &ms)
	{
		BufferedResponseBuilder  *r = reinterpret_cast<BufferedResponseBuilder*>(res.get());
		r->sendMessage(ms);
		return true;
	}
	fermat::http::RequestPtr createRequest()
	{
		std::shared_ptr<fermat::http::BufferedRequest> ret(new fermat::http::BufferedRequest);
		return ret;
	}
	bool onRequestReady(fermat::http::RequestPtr req, fermat::http::HttpServerSession *hss)
	{
		fermat::http::BufferedRequest *r = reinterpret_cast<fermat::http::BufferedRequest*>(req.get());
		BufferedResponseBuilder *lres = new BufferedResponseBuilder();
		fermat::http::ResponseBuilderPtr res(lres);
		bool allow = true;
		fermat::http::Url u(r->url());
		if(u.path() == "/hello") {
			lres->setUp();
		} else if(u.path() == "/big") {
			lres->setUpBig();
		} else if(fermat::Slice(u.path()).starts_with("/test_speed")){
			std::string len_str(u.path().data() + 11, u.path().size() - 11);
			int64_t lenth;
			bool r = fermat::NumberParser::atoix(len_str, lenth);
			if(!r || lenth <= 0) {
				allow = false;
				lres->setRes404();	
			} else {
				lres->setFixBody(lenth);
			}			
		} else {
			allow = false;
			lres->setRes404();
		}
		
		if(r->shouldKeepAlive()) {
			lres->setClose(false);
		} else {
			lres->setClose(true&allow);
		}
		hss->postResponse(res);
		return true;
	}

	bool onResponseWriteComplete(fermat::http::ResponseBuilderPtr& res, fermat::http::HttpServerSession *hss)
	{
		(void)res;
		(void)hss;
		return true;

	}
}
HttpServerTest::HttpServerTest(fermat::event::EventLoopPtr loop, 
								fermat::net::SocketAddress& listenAddr, 
								const std::string& name, 
								int threadnum)
				:_server(loop, listenAddr, name)
{
	_server.setThreadNum(threadnum);
	_server.setSessionBuilder(std::bind(& HttpServerTest::builder, this, std::placeholders::_1));
	_server.setSessionClear(std::bind(& HttpServerTest::clear, this, std::placeholders::_1));
	for(size_t i = 0; i < sizeof(detail::logbuf); i ++) {
		detail::logbuf[i] = 'a';
	}
	detail::logbuf[sizeof(detail::logbuf)-1] = '\0';
}

bool HttpServerTest::builder(fermat::http::HttpServerSession *hss)
{
	hss->setResponseWrite(std::bind(detail::writeResponse, std::placeholders::_1, std::placeholders::_2));
	hss->setRequestCreate(std::bind(detail::createRequest));
	hss->setRequestReadyCB(std::bind(detail::onRequestReady, std::placeholders::_1, std::placeholders::_2));
	hss->setResponseWriteComplete(std::bind(detail::onResponseWriteComplete, std::placeholders::_1, std::placeholders::_2));
	return true;
}
bool HttpServerTest::clear(fermat::http::HttpServerSession *hss)
{
	(void)hss;
	return true;
}


